package com.example.processor

import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated

data class FillProperty(
    val targetType: String,
    val idField: String,
    val propertyName: String,
    val serviceType: String,
    var targetPropertyList: Boolean = false,
    var serviceFunction: String = "findByIds",
)

class FillPropertyProcessorProvider : SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        val packageName = "org.opsli.modulars.em.util"
        val fileName = "EntityExtensions"
        val fillProperties = listOf(
//            FillProperty(
//                targetType = "LockCarHistory",
//                idField = "userId",
//                propertyName = "user",
//                serviceType = "UserServiceImpl"
//            ),
//            FillProperty(
//                targetType = "CardWallet",
//                idField = "userId",
//                propertyName = "user",
//                serviceType = "UserServiceImpl"
//            ),
            FillProperty(
                targetType = "EmVehicle",
                idField = "userId",
                propertyName = "userModel",
                serviceType = "UserServiceImpl",
                targetPropertyList = false,
            )
        )

        return object : SymbolProcessor {
            override fun process(resolver: Resolver): List<KSAnnotated> {
                val file = environment.codeGenerator.createNewFile(
                    dependencies = Dependencies(false),
                    packageName = packageName,
                    fileName = fileName
                )

                val generatedCode = buildString {
                    appendLine("package $packageName")
                    appendLine()

                    fillProperties.forEach { config ->
                        val propertyEntityName = config.propertyName.replaceFirstChar { it.uppercase() }
                        if (config.targetPropertyList) {
                            appendLine(
                                """
                                    |@JvmName("fill${propertyEntityName}For${config.targetType}")
                                    |fun List<${config.targetType}>.fill$propertyEntityName(service: ${config.serviceType}) {
                                    |    if (this.isEmpty()) return
                                    |    val ids = this.map { it.${config.idField} }.distinct()
                                    |    if (ids.isEmpty()) return
                                    |    val groupedElements = service.${config.serviceFunction}(ids).groupBy {
                                    |     it.${config.idField}
                                    |    }
                                    |    this.forEach {
                                    |    
                                    |    }
                                """.trimMargin()
                            )

                        } else {
                            appendLine(
                                """
                            |@JvmName("fill${propertyEntityName}For${config.targetType}")
                            |fun List<${config.targetType}>.fill$propertyEntityName(service: ${config.serviceType}) {
                            |    if (this.isEmpty()) return
                            |    val ids = this.map { it.${config.idField} }.distinct()
                            |
                            |    val propertyMap = service.${config.serviceFunction}(ids).associateBy { it.id }
                            |    this.forEach {
                            |        it.${config.propertyName} = propertyMap[it.${config.idField}]
                            |    }
                            |}
                            """.trimMargin()
                            )
                        }
                        appendLine()
                    }
                }

                file.write(generatedCode.toByteArray())
                file.close()

                return emptyList()
            }
        }
    }
}